"""
尘埃生成器

@author sean
@date 2021 - 08 - 13 10:43 上午
"""
import random
from threading import Timer

from cola.thing import Tetris
from cola.util.id_worker import worker
from cola.util.logger import logger


class RepeatingTimer(Timer):
    def run(self):
        while not self.finished.is_set():
            try:
                self.function(*self.args, **self.kwargs)
                self.finished.wait(self.interval)
            except Exception as e:
                logger.error('定时器 出现了问题', e)


class God:

    # 宽
    __width = 56

    # 高
    __height = 30

    # 组
    __group = {}

    # 定时器
    __timer_drop = None
    __timer_move = None
    __timer_frame = None

    def __init__(self, width, height, group):
        # 活动状态的尘埃列表
        self.dusts_pervert = {}
        # 固化状态的尘埃列表
        self.dusts_convert = {}
        # 亡者转变成的尘埃列表
        self.dusts_neutral = {}
        self.__group = group
        self.__width = width
        self.__height = height
        # 初始化定时器
        self.__timer_drop = RepeatingTimer(interval=13, function=self.drop)
        self.__timer_move = RepeatingTimer(interval=0.4, function=self.move)
        self.__timer_frame = RepeatingTimer(interval=0.066, function=self.frame_issue)

    # 放入组的帧空间空间中
    def join(self):
        frame_space = self.__group['frame_space']
        tetris = Tetris()
        points = tetris.points
        points[len(points):len(points)] = self.dusts_pervert.values()
        points[len(points):len(points)] = self.dusts_convert.values()
        points[len(points):len(points)] = self.dusts_neutral.values()
        frame_space[tetris.name] = tetris

    # 生成亡灵
    def generate(self, x: int, y: int):
        try:
            sign = worker.get_id()
            dust = {'x': x, 'y': y, 'state': 1, 'code': 0, 'sign': sign}
            self.dusts_neutral[sign] = dust
        except Exception as e:
            logger.error('drop 出现了问题', e)

    # 为所有用户的界面生成尘埃
    def drop(self):
        logger.info('drop...')
        try:
            x = random.randint(0, self.__width-1)
            sign = worker.get_id()
            dust = {'x': x, 'y': 0, 'state': 1, 'code': 0, 'sign': sign}
            self.dusts_pervert[sign] = dust
        except Exception as e:
            logger.error('drop 出现了问题', e)

    # 判断此位置是否已经有其它的点
    def exist(self, x: int, y: int):
        return self.exist_dust(x, y, self.dusts_pervert) \
               or self.exist_dust(x, y, self.dusts_convert) \
               or self.exist_dust(x, y, self.dusts_neutral) \
               or self.exist_snake(x, y)

    # 判断此位置是否有尘埃
    @staticmethod
    def exist_dust(x: int, y: int, dusts: dict):
        for key in list(dusts.keys()):
            point = dusts[key]
            if x == point['x'] and y == point['y']:
                return True
        return False

    # 判断此位置是否有蛇，忽略蛇尾
    def exist_snake(self, x: int, y: int):
        frame_space = self.__group['frame_space']
        for user in list(frame_space.values()):
            for point in user['points']:
                if x == point.get('x') and y == point.get('y') and point.get('state') not in (0, 3, 4):
                    return True
        return False

    # 尘埃随着时间移动
    def move(self):
        logger.info('move...')
        try:
            # dist无法直接遍历，需要先变成列表
            for key in list(self.dusts_pervert.keys()):
                point = self.dusts_pervert[key]
                y = point['y'] + 1
                if y >= self.__height or self.exist(point['x'], y):
                    point['state'] = 2
                    self.dusts_convert[key] = point
                    del self.dusts_pervert[key]
                else:
                    point['y'] = y
        except Exception as e:
            logger.error('move 出现了问题', e)

    # 发送帧数据
    def frame_issue(self):
        logger.info('frame_issue...')
        self.join()
        if 'users' not in self.__group or not self.__group['users']:
            logger.warn("区间内未找到活跃用户")
            return
        user = list(self.__group['users'].values())[0]
        user.render()

    # 启动定时器
    def start(self):
        self.__timer_drop.start()
        self.__timer_move.start()
        self.__timer_frame.start()

    # 停止定时器
    def stop(self):
        self.__timer_drop.cancel()
        self.__timer_move.cancel()
        self.__timer_frame.cancel()
